/*
 * ServerSocket.cpp
 *
 */

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sstream>
#include "ServerSocket.h"

namespace ipc {

ServerSocket::ServerSocket():Socket()
{
}

ServerSocket::~ServerSocket()
{
}

void ServerSocket::listen(int puerto, int cantidadConexiones)
{
	struct sockaddr_in	serv_addr;

	// INICIALIZACION DEL SERVER
	// Inicializar la estructura del socket:
	//		bzero(): borrar la estructura
	//		htonl(): Host-TO-Network Long integer (Byte order)
	//		htons(): Host-TO-Network Short integer (Byte order)


	bzero((char *) &serv_addr, sizeof(serv_addr));

	serv_addr.sin_family      = AF_INET; 				//familia protocolos TCP/IP
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);     // cualquier cliente
	serv_addr.sin_port 		  = htons((u_short)puerto); 		// port en formato red

	//Crear un socket para TCP (un Internet stream socket).
	if ( (m_Fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
		throw("Error no se puede abrir el stream socket");

	int optval = 1;

	//Reutilizar el socket en el server
	if(setsockopt(m_Fd, SOL_SOCKET,SO_REUSEADDR,(const char *) &optval, sizeof(optval))<0)
		throw("Error al cambiar los flags del socket");

	//setear Close on exec()
	if (fcntl(m_Fd, F_SETFD, FD_CLOEXEC) == -1)
		throw("Error al setear close on execv() socket");

	//Vincular el socket con la direccion local
	if (bind(m_Fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
	{
		std::stringstream ss;
		ss << "Error: no se puede hacer el bind:" <<strerror(errno);
		throw Exception(ss.str());
	}

	//Definir la cola de espera
	::listen(m_Fd, cantidadConexiones);
}

int ServerSocket::accept()
{
	int					socketSalida=-1;	    // socket conectado al cliente
	unsigned			clilen;	        	// longitud dir. cliente
	struct sockaddr_in	cli_addr;

	if(m_Fd <0)
		throw Exception("No se hizo el listen del socket");

	clilen = sizeof(cli_addr);

	socketSalida = ::accept(m_Fd, (struct sockaddr *) &cli_addr, &clilen);

	if(socketSalida < 0)
		throw Exception("Error haciendo el accept del socket");

	int optval = 1;

	//Activar keepalive
	if(setsockopt(socketSalida, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0)
			throw("Error al activar el keepalive");

	return socketSalida;
}

} /* namespace IPC */
